using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Epi.Data;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Reflection;
using System.CodeDom;
using System.CodeDom.Compiler;
using Microsoft.CSharp;

namespace Epi.Windows.Globalization.Forms
{
    /// <summary>
    /// Class Import
    /// </summary>
    public partial class Import : Form
    {

        #region Implementation

        /// <summary>
        /// Constructor for Import
        /// </summary>
        public Import()
        {
            InitializeComponent();
            ResourceTool.dbFactory = Epi.Data.DbDriverFactoryCreator.GetDbDriverFactory(Epi.Configuration.AccessDriver);
        }

        /// <summary>
        /// Error messages generated by CheckForInputSufficiency
        /// </summary>
        protected List<string> ErrorMessages = new List<string>();
        private IDbDriver selectedDataSource;
        private string applicationPath;
        delegate void VoidDelegate();

        private void OpenSelectedDataDriver()
        {
            ComboBoxItem selectedPlugIn = cmbDataSourcePlugIns.SelectedItem as ComboBoxItem;

            if (selectedPlugIn == null) throw new GeneralException("No data source plug-in is selected in combo box.");

            //IDbDriverFactory dbFactory = DatabaseFactoryCreator.GetDbDriverFactory(selectedPlugIn.Key);
            IConnectionStringGui dialog = ResourceTool.dbFactory.GetConnectionStringGuiForExistingDb();
            DialogResult result = ((Form)dialog).ShowDialog();
            IDbDriver db; 
            if (result == DialogResult.OK)
            {
                //ToDo: refine code here after remove db.connectstring, connectstringinfo ..
                bool success = false;
                db = ResourceTool.dbFactory.CreateDatabaseObject(dialog.DbConnectionStringBuilder);   
                db.ConnectionString = dialog.DbConnectionStringBuilder.ToString()  ;
                txtDataSource.Text = db.ConnectionDescription;

                try
                {
                    success = db.TestConnection();
                }
                catch
                {
                    success = false;
                    MessageBox.Show("Could not connect to selected data source.");
                }

                if (success)
                {
                    this.selectedDataSource = db;
                }
                else
                {
                    this.selectedDataSource = null;
                }

                this.RefreshForm();
            }
            else
            {
                this.selectedDataSource = null;
            }

        }

        /// <summary>
        /// ShowImportDialog()
        /// </summary>
        /// <param name="applicationPath"></param>
        public static void ShowImportDialog(string applicationPath)
        {
            Import instance = new Import();
            instance.applicationPath = applicationPath;
            instance.ShowDialog();
        }

        private void DisableForm()
          {
            if (this.InvokeRequired)
            {
                VoidDelegate del = new VoidDelegate(this.DisableForm);
                this.Invoke(del);
            }
            else
            {
                this.Cursor = Cursors.WaitCursor;
                this.panelMain.Enabled = false;
            }
        }

        private void EnableForm()
        {
            if (this.InvokeRequired)
            {
                VoidDelegate del = new VoidDelegate(this.EnableForm);
                this.Invoke(del);
            }
            else
            {
                this.panelMain.Enabled = true;
                this.Cursor = Cursors.Default;
                
            }
        }
        
        private void CloseForm()
        {
            if (this.InvokeRequired)
            {
                VoidDelegate del = new VoidDelegate(this.CloseForm);
                this.Invoke(del);
            }
            else
            {
                this.Close();
            }
        }

        private void ImportLanguage(string applicationPath)
        {
           
            string tableName = lvDataSourceObjects.SelectedItems[0].Text;
            string targetCulture = (ddlCultures.SelectedItem as DropDownListItem).Key.ToString();
            string installPath = applicationPath;

            System.Threading.WaitCallback callback = new System.Threading.WaitCallback(this.QueueInstallLanguageWorkerThread);

            object[] args = new object[4];
            args[0] = installPath;
            args[1] = targetCulture;
            args[2] = selectedDataSource;
            args[3] = tableName;

            System.Threading.ThreadPool.QueueUserWorkItem(callback, (object)args);
        }

        private void QueueInstallLanguageWorkerThread(object state)
        {
            object[] args = state as object[];
            string installPath = (string)args[0];
            string targetCulture = (string)args[1];
            IDbDriver dataSource = (IDbDriver)args[2];
            string tableName = (string)args[3];

            try
            {
                DisableForm();

                ResourceTool.ImportLanguage(installPath, targetCulture, dataSource, tableName, new AppendLogCallback(this.AppendToLog));
                CloseForm();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message,"Import Failed",MessageBoxButtons.OK,MessageBoxIcon.Information);
                EnableForm();
            }
            finally
            {
                
            }
        }

        void AppendToLog(string message)
        {
            if (this.statusStrip.InvokeRequired)
            {
                AppendLogCallback del = new AppendLogCallback(this.AppendToLog);
                this.statusStrip.Invoke(del, message);
            }
            else
            {
                //this.richTextBoxResults.Text = (message + Environment.NewLine) + this.richTextBoxResults.Text;
                this.toolStripStatusLabel.Text = message;
            }
        }
        void AppendToLog(string format, params object[] args)
        {
            this.AppendToLog(string.Format(format, args));

        }

        void SetupForm()
        {
            BindCultures();
            PopulateDataSourcePlugIns();
            RefreshForm();
        }

        void RefreshForm()
        {
            string itemText;

            lvDataSourceObjects.Groups.Clear();
            lvDataSourceObjects.Items.Clear();

            if (selectedDataSource is IDbDriver)
            {
                IDbDriver db = selectedDataSource as IDbDriver;
                this.txtDataSource.Text = db.ConnectionString;

                DataTable schemaTable = db.GetTableSchema();

                foreach (DataRow row in schemaTable.Rows)
                {
                    itemText = row[ColumnNames.SCHEMA_TABLE_NAME].ToString();
                    ListViewItem newItem = new ListViewItem(new string[] { itemText, itemText });
                    this.lvDataSourceObjects.Items.Add(newItem);
                }

                gbxShow.Enabled = true;

                if (lvDataSourceObjects.Items.Count > 0)
                {
                    lvDataSourceObjects.Items[0].Selected = true;
                    lvDataSourceObjects.Select();
                    Application.DoEvents();
                }

                
            }
            else
            {
                // Clear ...
                this.txtDataSource.Text = "(none)";
                this.lvDataSourceObjects.Items.Clear();// DataSource = null;

                gbxShow.Enabled = false;
            }

            this.CheckForInputSufficiency();

        }

        private void PopulateDataSourcePlugIns()
        {
            if (cmbDataSourcePlugIns.Items.Count == 0)
            {
                cmbDataSourcePlugIns.Items.Clear();

                //cmbDataSourcePlugIns.Items.Add(new ComboBoxItem(null, "Epi Info 7 Project", null));
                foreach (Epi.DataSets.Config.DataDriverRow row in Configuration.GetNewInstance().DataDrivers)
                {
                    cmbDataSourcePlugIns.Items.Add(new ComboBoxItem(row.Type, row.DisplayName, null));
                }
            }
            cmbDataSourcePlugIns.SelectedIndex = 0;
        }
     
        void BindCultures()
        {
            Dictionary<string, CultureInfo> cultureDictionary = new Dictionary<string, CultureInfo>();
            List<string> cultureList = new List<string>();

            // sort the list by english name

            foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures))
            {
                if (ci.Name == "") continue;

                if (cultureDictionary.ContainsKey(ci.EnglishName) == false)
                { 
                    cultureDictionary.Add(ci.EnglishName, ci);
                    cultureList.Add(ci.EnglishName);
                }
            }

            cultureList.Sort();

            // add sorted list to combobox 

            foreach (string cultureEnglishName in cultureList)
            {
                CultureInfo ci = cultureDictionary[cultureEnglishName];
                int i = ddlCultures.Items.Add(new DropDownListItem(ci.Name, cultureEnglishName, ci.NativeName));
                if (ci.Name == System.Threading.Thread.CurrentThread.CurrentUICulture.Name)
                {
                    this.ddlCultures.SelectedIndex = i;
                }

            }

            //TODO: If language is already installed, remove from list??

        }

        /// <summary>
        /// Enable buttons based on input
        /// </summary>
        public void CheckForInputSufficiency()
        {
            bool inputValid = ValidateInput();
            btnOK.Enabled = inputValid;
        }

        /// <summary>
        /// Validate the input
        /// </summary>
        /// <returns></returns>
        protected bool ValidateInput()
        {
            ErrorMessages.Clear();

            
            if (cmbDataSourcePlugIns.SelectedIndex == -1)
            {
                ErrorMessages.Add(Epi.SharedStrings.SPECIFY_DATAFORMAT);
            }
            if (string.IsNullOrEmpty(txtDataSource.Text))
            {
                ErrorMessages.Add(Epi.SharedStrings.SPECIFY_DATASOURCE);
            }
            if (this.lvDataSourceObjects.SelectedIndices.Count == 0)
            {
                ErrorMessages.Add(Epi.SharedStrings.SPECIFY_TABLE_OR_VIEW);
            }
            return (ErrorMessages.Count == 0);
        }
        #endregion

        #region Event handlers
        private void Import_Load(object sender, EventArgs e)
        {
            SetupForm();
        }

        private void lvDataSourceObjects_Resize(object sender, EventArgs e)
        {
            // leave space for scroll bar
            this.lvDataSourceObjects.Columns[0].Width = this.lvDataSourceObjects.Width - 25;
        }

        private void lvDataSourceObjects_SelectedIndexChanged(object sender, System.EventArgs e)
        {
            CheckForInputSufficiency();
        }

        private void btnOK_Click(object sender, EventArgs e)
        {
            this.ImportLanguage(applicationPath);
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.Cancel;
            this.Close();
        }

        private void btnFindDataSource_Click(object sender, EventArgs e)
        {
            this.OpenSelectedDataDriver();
        }

        private void cmbDataSourcePlugIns_SelectedIndexChanged(object sender, EventArgs e)
        {
            RefreshForm();
        }

        private void Import_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = false; 
        }

        private void ddlCultures_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
        #endregion

    }

    class ComboBoxItem
    {
        #region Implementation
        private string key;
        public string Key
        {
            get { return key; }
            set { key = value; }
        }

        private object value;
        public object Value
        {
            get { return this.value; }
            set { this.value = value; }
        }

        private string text;
        public string Text
        {
            get { return text; }
            set { text = value; }
        }

        public ComboBoxItem(string key, string text, object value)
        {
            this.key = key;
            this.value = value;
            this.text = text;
        }

        public override string ToString()
        {
            return text.ToString();
        }
        #endregion
    } 

}